/*
 * @(#)Protocol.java	Create on 2016-1-13 下午9:23:30
 * Copyright ? 2012 otooman.com. All Rights Reserved.
 * ASTEP PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package com.distribute.framework.core.lang;

import com.distribute.framework.core.web.helper.Utils;
import com.distribute.framework.core.web.util.Page;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;



/**
 * 标准协议定义bean
 * @author 刘代进
 * email: 27375334@qq.com
 * @version 2016-1-13
 */

public class Protocol implements java.io.Serializable{
	private static final long serialVersionUID = 1L;
	
	public Boolean success = true;//此次请求是否成功
	public String message;//全局错误信息
	public String error = "";//错误代码
	public String attach;//附加内容
	
	public Map data = new HashMap();//数据
	/*****************************结构定义***************************/
	//分页信息
	public static class PageInfo{
		public int index;//当前页
		public int total;//总页数
		public int count;//共多少条
		public int size;//一页多少条
		public boolean next;//是否有下一页
		public boolean prev;//是否有上一页
		public int getIndex() {
			return index;
		}
		public void setIndex(int index) {
			this.index = index;
		}
		public int getCount() {
			return count;
		}
		public void setCount(int count) {
			this.count = count;
		}
		public int getSize() {
			return size;
		}
		public void setSize(int size) {
			this.size = size;
		}
		public boolean isNext() {
			return next;
		}
		public void setNext(boolean next) {
			this.next = next;
		}
		public boolean isPrev() {
			return prev;
		}
		public void setPrev(boolean prev) {
			this.prev = prev;
		}
		public int getTotal() {
			return total;
		}
		public void setTotal(int total) {
			this.total = total;
		}
	}
	/*****************************结构定义***************************/
	
	public static void main(String...strings){
		/*List lst = new ArrayList();
		lst.add(Utils.add("df", "fds"));
		Utils.trace(new Protocol("fds","fds","fds").setTips(false, "结构定义").setList(lst).set("name", "刘代进"));*/
		System.out.println("abcdefg".substring(0,"abcdefg".length()));
	}
	
	@Override
	public String toString() {
		return Utils.json(this);
	}
	public Protocol() {
	}
	public Protocol(Boolean success, String message) {
		this.message = message;
		this.success = success;
	}
	public Protocol(Boolean success, String message,String error) {
		this.error = error;
		this.message = message;
		this.success = success;
	}
	public Protocol(Boolean success, String message,String error, String attach) {
		this.error = error;
		this.message = message;
		this.attach = attach;
		this.success = success;
	}
	public static Protocol create() {
		return new Protocol();
	}
	public static Protocol create(Boolean success) {
		return new Protocol(success,null);
	}
	public static Protocol create(Boolean success, String message) {
		return new Protocol(success,message);
	}
	public static Protocol create(Boolean success, String message,String error) {
		return new Protocol(success,message,error);
	}
	public static Protocol create(Boolean success, String message,String error, String attach) {
		return new Protocol(success,message,error,attach);
	}

	public Protocol reset(Boolean success) {
		this.setSuccess(success);
		return this;
	}
	public Protocol reset(Boolean success, String message) {
		this.setSuccess(success);
		this.setMessage(message);
		return this;
	}
	public Protocol reset(Boolean success, String message,String error) {
		this.setSuccess(success);
		this.setMessage(message);
		this.setError(error);
		return this;
	}
	public Protocol reset(Boolean success, String message,String error, String attach) {
		this.setSuccess(success);
		this.setMessage(message);
		this.setError(error);
		this.setAttach(attach);
		return this;
	}
	
	public Protocol setPageInfo(Page page) {
		PageInfo pageInfo = new PageInfo();
		pageInfo.count = (int) page.getCount();
		pageInfo.next = page.isNext();
		pageInfo.size = page.getSize();
		pageInfo.prev = page.isPrev();
		pageInfo.index = page.getIndex();
		pageInfo.total = page.getTotal();
		this.data.put("pageInfo", pageInfo);
		return this;
	}	
	public static abstract class BeanFormat<T> extends HashMap {
		public abstract Map format(T t);
		public BeanFormat<T> add(Object key,Object value){
			this.add(key, value);
			return this;
		}
	}
	public <T> Protocol setPage(Page<T> page,BeanFormat<T> beanFormat) {
		PageInfo pageInfo = new PageInfo();
		pageInfo.count = (int) page.getCount();
		pageInfo.next = page.isNext();
		pageInfo.size = page.getSize();
		pageInfo.prev = page.isPrev();
		pageInfo.index = page.getIndex();
		pageInfo.total = page.getTotal();
		this.data.put("pageInfo", pageInfo);
		this.setList(page.getResult(), beanFormat);
		return this;
	}
	public <T> Protocol setList(List<T> list,BeanFormat<T> beanFormat) {
		List lst = new ArrayList();
		for(T t:list){
			if(beanFormat!=null && beanFormat.format(t)!=null ){
				lst.add(beanFormat.format(t));
			}
		}
		this.setList(lst);
		return this;
	}
	public <T> Protocol setListByKey(String keyName,List<T> list,BeanFormat<T> beanFormat) {
		List lst = new ArrayList();
		for(T t:list){
			if(beanFormat!=null && beanFormat.format(t)!=null ){
				lst.add(beanFormat.format(t));
			}
		}
		this.setListByKeys(keyName,lst);
		return this;
	}
	public Protocol setListByKeys(String keyName,List lst) {
		this.data.put(keyName, lst);
		return this;
	}
	public Protocol setList(List list) {
		this.data.put("list", list);
		return this;
	}
	public <T> Protocol set(String key,List<T> list,BeanFormat<T> beanFormat) {
		List lst = new ArrayList();
		for(T t:list){
			if(beanFormat!=null && beanFormat.format(t)!=null ){
				lst.add(beanFormat.format(t));
			}
		}
		this.set(key, lst);
		return this;
	}
	public Protocol set(String key,Object value) {
		this.data.put(key, value);
		return this;
	}
	public <T> Protocol set(String key,Object value,String strKeys) {
		if(value instanceof List){
			List list = (List) value;
			List lst=new ArrayList();
			for(Object item:list){
				lst.add(beanToMap(item,strKeys));
			}
			this.data.put(key, lst);
		}else{
			this.data.put(key, beanToMap(value,strKeys));
		}
		return this;
	}
	private Object beanToMap(Object object, String strKeys) {
		if(object==null)return null;
		Map map = new HashMap();
		String[] keys = strKeys.split(",");
		for(String key:keys){
			keyToMap(object,key,map);
		}
		return map;
	}
	private void keyToMap(Object object, String skey, Map map) {
		int indexOf = skey.indexOf(".");
		String key = skey.substring(0, indexOf>-1?indexOf:skey.length());
		Object value = null;
		try{
			Method method = null;
			try{
				method = object.getClass().getMethod("get"+Utils.ForMat((indexOf>-1?"$":"")+key));
			}catch(Exception ex){
				method = object.getClass().getMethod("get"+Utils.ForMat(key));
			}
			method.setAccessible(true);
			value = method.invoke(object);
		}catch(Exception ex){
			ex.printStackTrace();
		}
		if(indexOf==-1){
			map.put(key, value);
		}else{//子map
			Map submap = (Map) map.get(key);
			if(submap==null)submap=new HashMap();
			keyToMap(value,skey.substring(indexOf+1),submap);
			map.put(key, submap);
		}
	}

	public static <T> T mapToBean(Map map, Class<? extends T> cls) {
		if(map==null)
			return null;
		Object object = null;
		try {
			object = cls.newInstance();
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
		Field[] fields = object.getClass().getDeclaredFields();
		for (Field field : fields) {
			field.setAccessible(true);
			try {

				String fieldName = field.getName();
				Class fieldType = field.getType().isArray() ? field.getType()
						.getComponentType() : field.getType();
				Class classType = getClassFromPrimitive(fieldType);

				Object convertValue = null;// 转换后的值

				Object objectValue = map.get(fieldName);// Map里的值
				if (objectValue == null)
					continue;
				if (field.getType().isArray()) {// 数组类型
					convertValue = convertListToArray(
							(java.util.List) objectValue, classType);
				} else if (classType == String.class) {
					convertValue = objectValue.toString();
				} else if (classType.getSuperclass() == java.lang.Number.class) {// java基本类型
					convertValue = classType.getMethod("valueOf", String.class)
							.invoke(null, objectValue.toString());
				} else if (classType == java.util.Date.class) {// 日期类型
					convertValue = new Date(
							Long.valueOf(objectValue.toString()));
				} else if (classType.getSuperclass() == java.lang.Object.class) {// 自定义类型
					convertValue = mapToBean((Map) objectValue,
							classType);
				} else if(classType == java.util.Map.class){
					convertValue = objectValue;
				} else if(classType == java.util.List.class){
					convertValue = objectValue;
				}else
					throw new RuntimeException("不可识别的类型" + cls.getName());

				field.set(object, convertValue);
			} catch (Exception ex) {
				System.err.println("INFO1005 - " + ex.getMessage());
			}
		}
		return (T) object;
	}
	private static Object convertListToArray(java.util.List list, Class cls) {
		try {
			Object retList = Array.newInstance(cls, list.size());
			Class classType = getClassFromPrimitive(cls);
			for (int i = 0; i < list.size(); i++) {
				Object objectValue = list.get(i);
				if (objectValue == null)
					continue;
				Object convertValue = null;
				if (classType == String.class
						|| classType.getSuperclass() == java.lang.Number.class) {// java基本类型
					convertValue = classType.getMethod("valueOf", String.class)
							.invoke(null, objectValue.toString());
				} else if (classType == java.util.Date.class) {// 日期类型
					convertValue = new Date(
							Long.valueOf(objectValue.toString()));
				} else if (classType.getSuperclass() == java.lang.Object.class) {// 自定义类型
					convertValue = mapToBean((Map) objectValue,
							classType);
				} else
					throw new RuntimeException("不可识别的类型" + cls.getName());

				Array.set(retList, i, convertValue);
			}
			return retList;
		} catch (Exception ex) {
			ex.printStackTrace();
			return null;
		}
	}
	/**
	 * 获取原始类对应的java类
	 * 
	 * @param classType
	 * @return
	 */
	private static Class getClassFromPrimitive(Class classType) {
		if (!classType.isPrimitive())
			return classType;
		String className = classType.getName();
		if (className.equals("byte"))
			return Byte.class;
		if (className.equals("short"))
			return Short.class;
		if (className.equals("int"))
			return Integer.class;
		if (className.equals("long"))
			return Long.class;
		if (className.equals("float"))
			return Float.class;
		if (className.equals("double"))
			return Double.class;
		return null;
	}

	public String getError() {
		return error;
	}

	public Protocol setError(String error) {
		this.error = error;
		return this;
	}

	public String getMessage() {
		return message;
	}

	public Protocol setMessage(String message) {
		this.message = message;
		return this;
	}

	public String getAttach() {
		return attach;
	}

	public Protocol setAttach(String attach) {
		this.attach = attach;
		return this;
	}

	public Map getData() {
		return data;
	}

	public Protocol setData(Map data) {
		this.data = data;
		return this;
	}

	public Boolean getSuccess() {
		return success;
	}

	public Protocol setSuccess(Boolean success) {
		this.success = success;
		return this;
	}
	
}